Add Salesforce chat widget to book details page#2873
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
9669126 to
30d6cc0
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as resolved.
This comment was marked as resolved.
- Add chat_book_details feature flag to shared-data.ts - Create Chat component with Salesforce Embedded Messaging integration - Integrate Chat component into BookDetails page with feature flag - Pass user information to Salesforce pre-chat form when available - Configure sProduct field as "Website" for Salesforce Related to CORE-1416 🤖 Generated with [Claude Code](https://claude.com/claude-code) lint Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix chat initialization to prevent re-initialization on userContext changes - Use ref to track initialization state - Derive stable user primitives to avoid unnecessary effect triggers - Only initialize once even if user context object changes - Set sProduct field for all users (logged in and anonymous) - Previously only set for logged-in users - Now always set to "Website" - Add all user information fields to pre-chat form - FirstName, LastName, Email, School in addition to UUID - Only set fields that are available - Add comprehensive tests for Chat component - Test script injection and initialization - Test user field handling for various scenarios - Test cleanup behavior - Test single initialization guarantee - Move Chat component to router level for persistence - Chat now renders at MainRoutes level in router.tsx - Maintains conversation state across navigation - Only shown on book details pages when feature flag enabled - Removed from BookDetails component 🤖 Generated with [Claude Code](https://claude.com/claude-code) Replace empty CSS rule with comment Lint Co-Authored-By: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
f58fd01 to
ef0e6a3
Compare
|
Docs PR opened: https://github.com/mintlify-community/docs-openstax-16c06674/pull/6 Added a book details chat widget section and documented the chat_book_details feature flag in the flags API reference. |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
- Add explicit hide/show logic for Salesforce chat widget - Hide chat elements on component unmount to prevent widget from staying visible - Show chat elements on component mount if widget was previously initialized - Targets Salesforce-injected DOM elements (.embeddedServiceHelpButton, etc.) - Ensures route/flag gating works correctly after initialization - Remove setTimeout from unit test - Test can assert immediately since no new onload event is triggered - Prevents test suite slowdown and potential flakiness - __salesforceChatInitialized flag prevents re-init without delay 🤖 Generated with [Claude Code](https://claude.com/claude-code) Shorten lines Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
8090398 to
e525469
Compare
mwvolo
left a comment
There was a problem hiding this comment.
I'm not sure if these copilot review comments are of concern.
It seemed like I was experiencing loading issues when I was testing it after hours, which I didn't see in-hours. The widget hides itself outside business hours, so I'm not sure if that could case some issues. When I went to a subjects page (tried in a couple browsers), nothing was loading.
Probably worth a little closer inspection.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Comment 1: Short-circuit script loading when bootstrap already exists - Check if window.embeddedservice_bootstrap exists on mount - If it exists, immediately set scriptLoaded=true and skip script injection - Prevents unnecessary script reload and speeds up widget re-display on remount - Eliminates potential delay or failure when re-showing hidden widget Comment 2: Only set initialization flag on successful init - Changed initEmbeddedMessaging() to return boolean success indicator - Only set window.__salesforceChatInitialized = true if init succeeded - Prevents permanently broken state if initialization fails - Allows retry on future mounts if initialization threw an error Comment 3: Update test to reflect new script loading behavior - Updated test comment and assertions to match short-circuit logic - Verifies no new script is injected on remount when bootstrap exists - Added explicit check that script count remains 0 after remount - Clarifies that scriptLoaded is set immediately via short-circuit Performance optimization in router.tsx: - Extract isLoggedIn as stable primitive before useMemo - Only re-evaluate showChat when isLoggedIn changes, not entire userContext - Reduces unnecessary re-renders when unrelated user properties update 🤖 Generated with [Claude Code](https://claude.com/claude-code) Consistent return value Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
**Issue:** `useUserContext()` only exposes `userModel` when `model.last_name` is truthy, which means logged-in users without a last name would be treated as anonymous and pre-chat fields wouldn't populate. **Resolution:** - Changed to derive user primitives from `userStatus` (always available) - Added fallback to `userModel` for compatibility - User info now extracted using: `userStatus?.uuid || userModel?.uuid` - Same pattern applied for firstName, lastName, email, school **Issue:** When short-circuiting because `window.embeddedservice_bootstrap` already exists, the effect returned a no-op cleanup (`() => undefined`), so the hide-on-unmount logic never ran, leaving the widget visible. **Resolution:** - Refactored to always return proper cleanup function - Moved script creation into conditional block - Cleanup now always hides chat widget on unmount, regardless of whether script was injected or short-circuited **Issue:** Using `userModel?.uuid` to determine login state can incorrectly treat some logged-in users as anonymous (same root cause as comment 1). **Resolution:** - Changed to: `userStatus?.uuid || userModel?.uuid` - Ensures `chat_logged_in` flag works correctly for all logged-in users - Site-wide chat now properly enabled when flag is set **Before:** - User info only available when `last_name` was present - Short-circuit path had no cleanup logic - Some logged-in users treated as anonymous **After:** - User info always accessible via `userStatus` - Cleanup always runs to hide widget on unmount - All logged-in users correctly identified 🤖 Generated with [Claude Code](https://claude.com/claude-code) Update router.tsx Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
203b28a to
a813084
Compare
This comment was marked as resolved.
This comment was marked as resolved.
Per Roy's review comment, consolidate isLoggedIn logic into a single canonical location in contexts/user.ts and have all other places use it. Changes: - Added isLoggedIn to useUserContext return value - Uses userStatus?.uuid || model?.uuid (the correct check) - Always available in context, even when userModel is not - Documented as the canonical way to check login state - Updated all places that previously defined isLoggedIn locally: 1. router.tsx - Removed local calculation, now uses context 2. form-header.tsx - Removed incorrect last_name check, now uses context 3. adoption.tsx - Removed incorrect last_name checks (2 instances), now uses context Benefits: - Single source of truth for login state - Fixes inconsistent implementations (some used last_name incorrectly) - Ensures all features work correctly for users without last names - Easier to maintain and update in the future Addresses Review 15 feedback. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Update adoption.tsx Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
948b012 to
57d4412
Compare
1. Clear script handlers on cleanup (Comment 1)
- Clear onload and onerror handlers before removing script
- Prevents setState-on-unmounted-component warnings
- Handlers can fire after unmount if network request completes late
2. Update PR description (Comments 2 & 3)
- Clarified that widget is hidden (not removed) to preserve session state
- Added explicit description of hide/show behavior when navigating
- Updated User Experience section with widget visibility details
- Updated Technical Implementation section
3. Add uuid to user context fallback branch (Comment 4)
- Expose uuid in fallback branch: {isLoggedIn, userStatus, myOpenStaxUser, uuid: userStatus?.uuid}
- Makes context shape consistent across both branches
- Consumers can now reliably destructure uuid alongside isLoggedIn
- uuid will be undefined for truly anonymous users
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
I've addressed all 4 unresolved Copilot review comments from Review 16. Here's a summary of the changes: Changes Made1. Clear script handlers on cleanup (Comment 1)Issue: The cleanup function removed the Resolution:
2. Update PR description to clarify hiding behavior (Comments 2 & 3)Issue:
Resolution:
3. Add uuid to user context fallback branch (Comment 4)Issue: Resolution:
Technical SummaryRoot causes:
All fixes committed and pushed. The implementation now:
Ready for final review! @RoyEJohnson |
|
The latest version is deployed to Dev (tag is |
Summary
Adds Salesforce Embedded Messaging chat widget with flexible feature flag control. The chat widget persists across navigation to maintain conversation state and can be enabled for:
Related to: https://openstax.atlassian.net/browse/CORE-1416
Changes
shared-data.ts:chat_book_details- Enable chat on book details pageschat_subjects- Enable chat on subjects pageschat_contact- Enable chat on contact pagechat_logged_in- Enable chat site-wide for logged-in usersChatcomponent atsrc/app/components/chat/00DU0000000Kwchand deploymentWeb_Messaging_DeploymentsProductfield as "Website" for all usersChatcomponent into router atMainRouteslevelchat_logged_inflag is enabledchat_book_detailsflag is enabledchat_subjectsflag is enabledchat_contactflag is enabledChatcomponentisLoggedInlogic inuseUserContextfor consistencyImplementation Details
Following the pattern from the Accounts repository, adapted for React/Preact architecture.
Feature Flags
The chat widget is controlled by multiple CMS feature flags that need to be created at https://openstax.org/django-admin/api/featureflag/:
/details/*)/subjects/*)/contact)Flags are additive - if multiple flags are enabled, chat will show on all applicable pages.
User Experience
sProductis still set to "Website"display: none) when navigating away from chat-enabled pagesTechnical Implementation
MainRoutes) rather than page levelwindow.__salesforceChatInitializedflag to track initialization globallyuserContext.userStatusto avoid unnecessary effect triggerswindow.embeddedservice_bootstrapobject on component remount to maintain sessionTesting
Review Comments Addressed
sProductfor all users (not just logged-in users)isLoggedInlogic in useUserContext🤖 Generated with Claude Code